home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /* $Revision: 1.9 $ */
- /*
- * paperplane can be compiled to use a "single visual" for the entire window
- * hierarchy and render OpenGL into a standard Motif drawing area widget:
- *
- * cc -o sv_paperplane paperplane.c -DnoGLwidget -lGL -lXm -lXt -lX11 -lm
- *
- * Or paperplane can be compiled to use the default visual for most of
- * the window hierarchy but render OpenGL into a special "OpenGL widget":
- *
- * cc -o glw_paperplane paperplane.c -lGLw -lGL -lXm -lXt -lX11 -lm
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <math.h>
- #include <Xm/MainW.h>
- #include <Xm/RowColumn.h>
- #include <Xm/PushB.h>
- #include <Xm/ToggleB.h>
- #include <Xm/CascadeB.h>
- #include <Xm/Frame.h>
- #ifdef noGLwidget
- #include <Xm/DrawingA.h> /* Motif drawing area widget */
- #else
- #ifdef noMotifGLwidget
- #include <GL/GLwDrawA.h> /* pure Xt OpenGL drawing area widget */
- #else
- #include <GL/GLwMDrawA.h> /* Motif OpenGL drawing area widget */
- #endif
- #endif
- #include <X11/keysym.h>
- #include <GL/gl.h>
- #include <GL/glu.h>
- #include <GL/glx.h>
-
- static int dblBuf[] = {
- GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16,
- GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
- None
- };
- static int *snglBuf = &dblBuf[1];
- static String fallbackResources[] = {
- #ifdef IRIX_5_2_or_higher
- "*sgiMode: true", /* try to enable IRIX 5.2+ look & feel */
- "*useSchemes: all", /* and SGI schemes */
- #endif
- "*title: OpenGL paper plane demo",
- "*glxarea*width: 300", "*glxarea*height: 300", NULL
- };
- Display *dpy;
- GLboolean doubleBuffer = GL_TRUE, moving = GL_FALSE, made_current = GL_FALSE;
- XtAppContext app;
- XtWorkProcId workId = 0;
- Widget toplevel, mainw, menubar, menupane, btn, cascade, frame, glxarea;
- GLXContext cx;
- XVisualInfo *vi;
- #ifdef noGLwidget
- Colormap cmap;
- #endif
- Arg menuPaneArgs[1], args[1];
-
- #define MAX_PLANES 15
-
- struct {
- float speed; /* zero speed means not flying */
- GLfloat red, green, blue;
- float theta;
- float x, y, z, angle;
- } planes[MAX_PLANES];
-
- #define v3f glVertex3f /* v3f was the short IRIS GL name for glVertex3f */
-
- void draw(Widget w)
- {
- GLfloat red, green, blue;
- int i;
-
- glClear(GL_DEPTH_BUFFER_BIT);
- /* paint black to blue smooth shaded polygon for background */
- glDisable(GL_DEPTH_TEST);
- glShadeModel(GL_SMOOTH);
- glBegin(GL_POLYGON);
- glColor3f(0.0, 0.0, 0.0);
- v3f(-20, 20, -19); v3f(20, 20, -19);
- glColor3f(0.0, 0.0, 1.0);
- v3f(20, -20, -19); v3f(-20, -20, -19);
- glEnd();
- /* paint planes */
- glEnable(GL_DEPTH_TEST);
- glShadeModel(GL_FLAT);
- for (i = 0; i < MAX_PLANES; i++)
- if (planes[i].speed != 0.0) {
- glPushMatrix();
- glTranslatef(planes[i].x, planes[i].y, planes[i].z);
- glRotatef(290.0, 1.0, 0.0, 0.0);
- glRotatef(planes[i].angle, 0.0, 0.0, 1.0);
- glScalef(1.0 / 3.0, 1.0 / 4.0, 1.0 / 4.0);
- glTranslatef(0.0, -4.0, -1.5);
- glBegin(GL_TRIANGLE_STRIP);
- /* left wing */
- v3f(-7.0, 0.0, 2.0); v3f(-1.0, 0.0, 3.0);
- glColor3f(red = planes[i].red, green = planes[i].green,
- blue = planes[i].blue);
- v3f(-1.0, 7.0, 3.0);
- /* left side */
- glColor3f(0.6 * red, 0.6 * green, 0.6 * blue);
- v3f(0.0, 0.0, 0.0); v3f(0.0, 8.0, 0.0);
- /* right side */
- v3f(1.0, 0.0, 3.0); v3f(1.0, 7.0, 3.0);
- /* final tip of right wing */
- glColor3f(red, green, blue);
- v3f(7.0, 0.0, 2.0);
- glEnd();
- glPopMatrix();
- }
- if (doubleBuffer) glXSwapBuffers(dpy, XtWindow(w));
- if(!glXIsDirect(dpy, cx))
- glFinish(); /* avoid indirect rendering latency from queuing */
- #ifdef DEBUG
- { /* for help debugging, report any OpenGL errors that occur per frame */
- GLenum error;
- while((error = glGetError()) != GL_NO_ERROR)
- fprintf(stderr, "GL error: %s\n", gluErrorString(error));
- }
- #endif
- }
-
- void tick_per_plane(int i)
- {
- float theta = planes[i].theta += planes[i].speed;
- planes[i].z = -9 + 4 * cos(theta);
- planes[i].x = 4 * sin(2 * theta);
- planes[i].y = sin(theta / 3.4) * 3;
- planes[i].angle = ((atan(2.0) + M_PI_2) * sin(theta) - M_PI_2) * 180 / M_PI;
- if (planes[i].speed < 0.0) planes[i].angle += 180;
- }
-
- void add_plane(void)
- {
- int i;
-
- for (i = 0; i < MAX_PLANES; i++)
- if (planes[i].speed == 0) {
-
- #define SET_COLOR(r,g,b) \
- planes[i].red=r; planes[i].green=g; planes[i].blue=b; break;
-
- switch (random() % 6) {
- case 0: SET_COLOR(1.0, 0.0, 0.0); /* red */
- case 1: SET_COLOR(1.0, 1.0, 1.0); /* white */
- case 2: SET_COLOR(0.0, 1.0, 0.0); /* green */
- case 3: SET_COLOR(1.0, 0.0, 1.0); /* magenta */
- case 4: SET_COLOR(1.0, 1.0, 0.0); /* yellow */
- case 5: SET_COLOR(0.0, 1.0, 1.0); /* cyan */
- }
- planes[i].speed = (random() % 20) * 0.001 + 0.02;
- if (random() & 0x1) planes[i].speed *= -1;
- planes[i].theta = ((float) (random() % 257)) * 0.1111;
- tick_per_plane(i);
- if (!moving) draw(glxarea);
- return;
- }
- XBell(dpy, 100); /* can't add any more planes */
- }
-
- void remove_plane(void)
- {
- int i;
-
- for (i = MAX_PLANES - 1; i >= 0; i--)
- if (planes[i].speed != 0) {
- planes[i].speed = 0;
- if (!moving) draw(glxarea);
- return;
- }
- XBell(dpy, 100); /* no more planes to remove */
- }
-
- void resize(Widget w, XtPointer data, XtPointer callData)
- {
- Dimension width, height;
-
- if(made_current) {
- XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL);
- glViewport(0, 0, (GLint) width, (GLint) height);
- }
- }
-
- void tick(void)
- {
- int i;
-
- for (i = 0; i < MAX_PLANES; i++)
- if (planes[i].speed != 0.0) tick_per_plane(i);
- }
-
- Boolean animate(XtPointer data)
- {
- tick();
- draw(glxarea);
- return False; /* leave work proc active */
- }
-
- void toggle(void)
- {
- moving = !moving; /* toggle */
- if (moving)
- workId = XtAppAddWorkProc(app, animate, NULL);
- else
- XtRemoveWorkProc(workId);
- }
-
- void quit(Widget w, XtPointer data, XtPointer callData)
- {
- exit(0);
- }
-
- void input(Widget w, XtPointer data, XtPointer callData)
- {
- XmDrawingAreaCallbackStruct *cd = (XmDrawingAreaCallbackStruct *) callData;
- char buf[1];
- KeySym keysym;
- int rc;
-
- if(cd->event->type == KeyPress)
- if(XLookupString((XKeyEvent *) cd->event, buf, 1, &keysym, NULL) == 1)
- switch (keysym) {
- case XK_space:
- if (!moving) { /* advance one frame if not in motion */
- tick();
- draw(w);
- }
- break;
- case XK_Escape:
- exit(0);
- }
- }
-
- void map_state_changed(Widget w, XtPointer data, XEvent * event, Boolean * cont)
- {
- switch (event->type) {
- case MapNotify:
- if (moving && workId != 0) workId = XtAppAddWorkProc(app, animate, NULL);
- break;
- case UnmapNotify:
- if (moving) XtRemoveWorkProc(workId);
- break;
- }
- }
-
- main(int argc, char *argv[])
- {
- toplevel = XtAppInitialize(&app, "Paperplane", NULL, 0, &argc, argv,
- fallbackResources, NULL, 0);
- dpy = XtDisplay(toplevel);
- /* find an OpenGL-capable RGB visual with depth buffer */
- vi = glXChooseVisual(dpy, DefaultScreen(dpy), dblBuf);
- if (vi == NULL) {
- vi = glXChooseVisual(dpy, DefaultScreen(dpy), snglBuf);
- if (vi == NULL)
- XtAppError(app, "no RGB visual with depth buffer");
- doubleBuffer = GL_FALSE;
- }
- /* create an OpenGL rendering context */
- cx = glXCreateContext(dpy, vi, /* no display list sharing */ None,
- /* favor direct */ GL_TRUE);
- if (cx == NULL)
- XtAppError(app, "could not create rendering context");
- /* create an X colormap since probably not using default visual */
- #ifdef noGLwidget
- cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
- vi->visual, AllocNone);
- /*
- * Establish the visual, depth, and colormap of the toplevel
- * widget _before_ the widget is realized.
- */
- XtVaSetValues(toplevel, XtNvisual, vi->visual, XtNdepth, vi->depth,
- XtNcolormap, cmap, NULL);
- #endif
- XtAddEventHandler(toplevel, StructureNotifyMask, False,
- map_state_changed, NULL);
- mainw = XmCreateMainWindow(toplevel, "mainw", NULL, 0);
- XtManageChild(mainw);
- /* create menu bar */
- menubar = XmCreateMenuBar(mainw, "menubar", NULL, 0);
- XtManageChild(menubar);
- #ifdef noGLwidget
- /* Hack around Xt's unfortunate default visual inheritance. */
- XtSetArg(menuPaneArgs[0], XmNvisual, vi->visual);
- menupane = XmCreatePulldownMenu(menubar, "menupane", menuPaneArgs, 1);
- #else
- menupane = XmCreatePulldownMenu(menubar, "menupane", NULL, 0);
- #endif
- btn = XmCreatePushButton(menupane, "Quit", NULL, 0);
- XtAddCallback(btn, XmNactivateCallback, quit, NULL);
- XtManageChild(btn);
- XtSetArg(args[0], XmNsubMenuId, menupane);
- cascade = XmCreateCascadeButton(menubar, "File", args, 1);
- XtManageChild(cascade);
- #ifdef noGLwidget
- menupane = XmCreatePulldownMenu(menubar, "menupane", menuPaneArgs, 1);
- #else
- menupane = XmCreatePulldownMenu(menubar, "menupane", NULL, 0);
- #endif
- btn = XmCreateToggleButton(menupane, "Motion", NULL, 0);
- XtAddCallback(btn, XmNvalueChangedCallback, (XtCallbackProc)toggle, NULL);
- XtManageChild(btn);
- btn = XmCreatePushButton(menupane, "Add plane", NULL, 0);
- XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)add_plane, NULL);
- XtManageChild(btn);
- btn = XmCreatePushButton(menupane, "Remove plane", NULL, 0);
- XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)remove_plane, NULL);
- XtManageChild(btn);
- XtSetArg(args[0], XmNsubMenuId, menupane);
- cascade = XmCreateCascadeButton(menubar, "Planes", args, 1);
- XtManageChild(cascade);
- /* create framed drawing area for OpenGL rendering */
- frame = XmCreateFrame(mainw, "frame", NULL, 0);
- XtManageChild(frame);
- #ifdef noGLwidget
- glxarea = XtVaCreateManagedWidget("glxarea", xmDrawingAreaWidgetClass,
- frame, NULL);
- #else
- #ifdef noMotifGLwidget
- /* notice glwDrawingAreaWidgetClass lacks an 'M' */
- glxarea = XtVaCreateManagedWidget("glxarea", glwDrawingAreaWidgetClass,
- #else
- glxarea = XtVaCreateManagedWidget("glxarea", glwMDrawingAreaWidgetClass,
- #endif
- frame, GLwNvisualInfo, vi, NULL);
- #endif
- XtAddCallback(glxarea, XmNexposeCallback, (XtCallbackProc)draw, NULL);
- XtAddCallback(glxarea, XmNresizeCallback, resize, NULL);
- XtAddCallback(glxarea, XmNinputCallback, input, NULL);
- /* set up application's window layout */
- XmMainWindowSetAreas(mainw, menubar, NULL, NULL, NULL, frame);
- XtRealizeWidget(toplevel);
- /*
- * Once widget is realized (ie, associated with a created X window), we
- * can bind the OpenGL rendering context to the window.
- */
- glXMakeCurrent(dpy, XtWindow(glxarea), cx);
- made_current = GL_TRUE;
- /* setup OpenGL state */
- glClearDepth(1.0);
- glClearColor(0.0, 0.0, 0.0, 0.0);
- glMatrixMode(GL_PROJECTION);
- glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 20);
- glMatrixMode(GL_MODELVIEW);
- /* add three initial random planes */
- srandom(getpid());
- add_plane(); add_plane(); add_plane();
- /* start event processing */
- XtAppMainLoop(app);
- }
-